﻿using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.VisualBasic.FileIO;

namespace FBProject.BusinessLogic.FBImport
{
    public abstract class FBImportBase
    {

        private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger(typeof(FBImportBase));

        public virtual IDictionary<string, ExternalTask> ReadExternalTasks()
        {
            return null;
        }

        protected ExternalColumnIndexes GetColumnIndexes(string[] columnNames)
        {
            var csvColumnIndexes = new ExternalColumnIndexes();

            for (int columnIndex = 0; columnIndex <= columnNames.GetUpperBound(0); columnIndex++)
            {
                var externalColumnName = columnNames[columnIndex].ToUpperInvariant();
                if (ExternalColumnIndexes.PropertiesWithExternalName.ContainsKey(externalColumnName))
                {
                    var propertyInfo = ExternalColumnIndexes.PropertiesWithExternalName[externalColumnName];
                    propertyInfo.SetValue(csvColumnIndexes, columnIndex, null);
                }
            }

            var missingColumns = csvColumnIndexes.GetMissingColumns();
            if ((missingColumns != null) && (missingColumns.Count > 0))
            {
                throw new MissingColumnsInSourceFileException(missingColumns);
            }

            return csvColumnIndexes;
        }

        protected static ExternalTask GetExternalTask(ExternalColumnIndexes columnIndexes, object[] values)
        {
            var externalTask = new ExternalTask();

            externalTask.TaskNumber = GetStringValue(values[columnIndexes.TaskNumber]);
            externalTask.Name = GetStringValue(values[columnIndexes.Name]);
            externalTask.Estimate = GetEstimate(values[columnIndexes.Estimate]);
            externalTask.RemainingWork = GetRemainingWork(values[columnIndexes.ElapsedTime], externalTask.Estimate);
            externalTask.Priority = GetPriority(values[columnIndexes.Priority]);
            externalTask.Completed = GetCompleted(values[columnIndexes.Status]);
            externalTask.Milestone = GetMilestone(values[columnIndexes.Milestone]);
            externalTask.Resource = GetStringValue(values[columnIndexes.Resource]);

            return externalTask;
        }

        private static int GetRemainingWork(object externalElapsedTime, int estimate)
        {
            double numericValue;
            if (Double.TryParse(GetStringValue(externalElapsedTime), out numericValue))
            {
                return estimate - (int)(numericValue * 60);
            }
            else
            {
                return estimate;
            }
        }

        private static int GetEstimate(object externalEstimate)
        {
            double numericValue;
            if (Double.TryParse(GetStringValue(externalEstimate), out numericValue))
            {
                return (int)(numericValue * 60);
            }
            else
            {
                return 0;
            }
        }

        private static string GetStringValue(object value)
        {
            if (value == null)
            {
                return string.Empty;
            }
            else
            {
                return value.ToString();
            }
        }

        private static bool GetCompleted(object externalStatus)
        {
            var externalStatusAsString = externalStatus as string;
            if (externalStatusAsString != null)
            {
                return !externalStatusAsString.ToUpperInvariant().StartsWith("active", StringComparison.OrdinalIgnoreCase);
            }
            return false;
        }

        private static short GetPriority(object externalPriority)
        {
            short priority;
            if (externalPriority != null)
            {
                if (short.TryParse(externalPriority.ToString().Substring(0, 1), out priority))
                {
                    return (short)((10 - priority) * 100);
                }
                else
                {
                    Logger.WarnFormat("GetPriority() - Cannot convert priority \"{0}\"", externalPriority);
                }
            }
            return 0;
        }

        private static string GetMilestone(object externalMilestone)
        {
            var externalMilestoneAsString = externalMilestone as string;
            if (externalMilestoneAsString != null)
            {
                int position = externalMilestoneAsString.IndexOf(":", StringComparison.OrdinalIgnoreCase);
                if (position >= 0)
                    return externalMilestoneAsString.Substring(0, position);
                else
                    return externalMilestoneAsString;
            }
            return string.Empty;
        }
    }
}
